home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / DJGPP / DJLSR111.ZIP / libsrc / c / io / doprnt.c < prev    next >
C/C++ Source or Header  |  1993-10-02  |  19KB  |  753 lines

  1. /* This is file DOPRNT.C */
  2. /* This file may have been modified by DJ Delorie (Jan 1991).  If so,
  3. ** these modifications are Coyright (C) 1993 DJ Delorie, 24 Kirsten Ave,
  4. ** Rochester NH, 03867-2954, USA.
  5. */
  6.  
  7. /*
  8.  * Copyright (c) 1988 Regents of the University of California.
  9.  * All rights reserved.
  10.  *
  11.  * Redistribution and use in source and binary forms are permitted provided
  12.  * that: (1) source distributions retain this entire copyright notice and
  13.  * comment, and (2) distributions including binaries display the following
  14.  * acknowledgement:  ``This product includes software developed by the
  15.  * University of California, Berkeley and its contributors'' in the
  16.  * documentation or other materials provided with the distribution and in
  17.  * all advertising materials mentioning features or use of this software.
  18.  * Neither the name of the University nor the names of its contributors may
  19.  * be used to endorse or promote products derived from this software without
  20.  * specific prior written permission.
  21.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  22.  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  23.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  24.  */
  25.  
  26. #if defined(LIBC_SCCS) && !defined(lint)
  27. static char sccsid[] = "@(#)doprnt.c    5.39 (Berkeley) 6/28/90";
  28. #endif /* LIBC_SCCS and not lint */
  29.  
  30. #define _doprnt ____doprnt
  31. #include <sys/types.h>
  32. #include <varargs.h>
  33. #include <stdio.h>
  34. #include <ctype.h>
  35. #undef _doprnt
  36.  
  37. /* 11-bit exponent (VAX G floating point) is 308 decimal digits */
  38. #define    MAXEXP        308
  39. /* 128 bit fraction takes up 39 decimal digits; max reasonable precision */
  40. #define    MAXFRACT    39
  41.  
  42. #define    DEFPREC        6
  43. #define    DEFLPREC    14
  44.  
  45. #define    BUF        (MAXEXP+MAXFRACT+1)    /* + decimal point */
  46.  
  47. #define    PUTC(ch)    (void) putc(ch, fp)
  48.  
  49. #define ARG(basetype) \
  50.     _ulong = flags&LONGINT ? va_arg(argp, long basetype) : \
  51.         flags&SHORTINT ? (short basetype)va_arg(argp, int) : \
  52.         va_arg(argp, int)
  53.  
  54. static int nan = 0;
  55.  
  56. #if 0
  57. #define    todigit(c)    ((c) - '0')
  58. #define    tochar(n)    ((n) + '0')
  59. #else
  60. static int todigit(char c)
  61. {
  62.   if (c<='0') return 0;
  63.   if (c>='9') return 9;
  64.   return c-'0';
  65. }
  66. static char tochar(int n)
  67. {
  68.   if (n>=9) return '9';
  69.   if (n<=0) return '0';
  70.   return n+'0';
  71. }
  72. #endif
  73.  
  74. /* have to deal with the negative buffer count kludge */
  75. #define    NEGATIVE_COUNT_KLUDGE
  76.  
  77. #define    LONGINT        0x01        /* long integer */
  78. #define    LONGDBL        0x02        /* long double; unimplemented */
  79. #define    SHORTINT    0x04        /* short integer */
  80. #define    ALT        0x08        /* alternate form */
  81. #define    LADJUST        0x10        /* left adjustment */
  82. #define    ZEROPAD        0x20        /* zero (as opposed to blank) pad */
  83. #define    HEXPREFIX    0x40        /* add 0x or 0X prefix */
  84.  
  85. _doprnt(fmt0, argp, fp)
  86.     const char *fmt0;
  87.     va_list argp;
  88.     FILE *fp;
  89. {
  90.     u_char *fmt;        /* format string */
  91.     int ch;            /* character from fmt */
  92.     int cnt;        /* return value accumulator */
  93.     int n;            /* random handy integer */
  94.     char *t;        /* buffer pointer */
  95.     double _double;        /* double precision arguments %[eEfgG] */
  96.     u_long _ulong;        /* integer arguments %[diouxX] */
  97.     int base;        /* base for [diouxX] conversion */
  98.     int dprec;        /* decimal precision in [diouxX] */
  99.     int fieldsz;        /* field size expanded by sign, etc */
  100.     int flags;        /* flags as above */
  101.     int fpprec;        /* `extra' floating precision in [eEfgG] */
  102.     int prec;        /* precision from format (%.3d), or -1 */
  103.     int realsz;        /* field size expanded by decimal precision */
  104.     int size;        /* size of converted field or string */
  105.     int width;        /* width from format (%8d), or 0 */
  106.     char sign;        /* sign prefix (' ', '+', '-', or \0) */
  107.     char softsign;        /* temporary negative sign for floats */
  108.     char *digs;        /* digits for [diouxX] conversion */
  109.     char buf[BUF];        /* space for %c, %[diouxX], %[eEfgG] */
  110.  
  111.     if (fp->_flag & _IORW) {
  112.         fp->_flag |= _IOWRT;
  113.         fp->_flag &= ~(_IOEOF|_IOREAD);
  114.     }
  115.     if ((fp->_flag & _IOWRT) == 0)
  116.         return (EOF);
  117.  
  118.     fmt = fmt0;
  119.     digs = "0123456789abcdef";
  120.     for (cnt = 0;; ++fmt) {
  121.         n = fp->_cnt;
  122.         for (t = (char *)fp->_ptr; (ch = *fmt) && ch != '%';
  123.              ++cnt, ++fmt)
  124.             if (--n < 0
  125. #ifdef NEGATIVE_COUNT_KLUDGE
  126.                 && (!(fp->_flag & _IOLBF) || -n >= fp->_bufsiz)
  127. #endif
  128.                 || ch == '\n' && fp->_flag & _IOLBF) {
  129.                 fp->_cnt = n;
  130.                 fp->_ptr = t;
  131.                 (void) _flsbuf((u_char)ch, fp);
  132.                 n = fp->_cnt;
  133.                 t = (char *)fp->_ptr;
  134.             } else
  135.                 *t++ = ch;
  136.         fp->_cnt = n;
  137.         fp->_ptr = t;
  138.         if (!ch)
  139.             return (cnt);
  140.  
  141.         flags = 0; dprec = 0; fpprec = 0; width = 0;
  142.         prec = -1;
  143.         sign = '\0';
  144.  
  145. rflag:        switch (*++fmt) {
  146.         case ' ':
  147.             /*
  148.              * ``If the space and + flags both appear, the space
  149.              * flag will be ignored.''
  150.              *    -- ANSI X3J11
  151.              */
  152.             if (!sign)
  153.                 sign = ' ';
  154.             goto rflag;
  155.         case '#':
  156.             flags |= ALT;
  157.             goto rflag;
  158.         case '*':
  159.             /*
  160.              * ``A negative field width argument is taken as a
  161.              * - flag followed by a  positive field width.''
  162.              *    -- ANSI X3J11
  163.              * They don't exclude field widths read from args.
  164.              */
  165.             if ((width = va_arg(argp, int)) >= 0)
  166.                 goto rflag;
  167.             width = -width;
  168.             /* FALLTHROUGH */
  169.         case '-':
  170.             flags |= LADJUST;
  171.             goto rflag;
  172.         case '+':
  173.             sign = '+';
  174.             goto rflag;
  175.         case '.':
  176.             if (*++fmt == '*')
  177.                 n = va_arg(argp, int);
  178.             else {
  179.                 n = 0;
  180.                 while (isascii(*fmt) && isdigit(*fmt))
  181.                     n = 10 * n + todigit(*fmt++);
  182.                 --fmt;
  183.             }
  184.             prec = n < 0 ? -1 : n;
  185.             goto rflag;
  186.         case '0':
  187.             /*
  188.              * ``Note that 0 is taken as a flag, not as the
  189.              * beginning of a field width.''
  190.              *    -- ANSI X3J11
  191.              */
  192.             flags |= ZEROPAD;
  193.             goto rflag;
  194.         case '1': case '2': case '3': case '4':
  195.         case '5': case '6': case '7': case '8': case '9':
  196.             n = 0;
  197.             do {
  198.                 n = 10 * n + todigit(*fmt);
  199.             } while (isascii(*++fmt) && isdigit(*fmt));
  200.             width = n;
  201.             --fmt;
  202.             goto rflag;
  203.         case 'L':
  204.             flags |= LONGDBL;
  205.             goto rflag;
  206.         case 'h':
  207.             flags |= SHORTINT;
  208.             goto rflag;
  209.         case 'l':
  210.             flags |= LONGINT;
  211.             goto rflag;
  212.         case 'c':
  213.             *(t = buf) = va_arg(argp, int);
  214.             size = 1;
  215.             sign = '\0';
  216.             goto pforw;
  217.         case 'D':
  218.             flags |= LONGINT;
  219.             /*FALLTHROUGH*/
  220.         case 'd':
  221.         case 'i':
  222.             ARG(int);
  223.             if ((long)_ulong < 0) {
  224.                 _ulong = -_ulong;
  225.                 sign = '-';
  226.             }
  227.             base = 10;
  228.             goto number;
  229.         case 'e':
  230.         case 'E':
  231.         case 'f':
  232.         case 'g':
  233.         case 'G':
  234.             _double = va_arg(argp, double);
  235.             /*
  236.              * don't do unrealistic precision; just pad it with
  237.              * zeroes later, so buffer size stays rational.
  238.              */
  239.             if (prec > MAXFRACT) {
  240.                 if (*fmt != 'g' && *fmt != 'G' || (flags&ALT))
  241.                     fpprec = prec - MAXFRACT;
  242.                 prec = MAXFRACT;
  243.             }
  244.             else if (prec == -1)
  245.             {
  246.                 if (flags&LONGINT)
  247.                     prec = DEFLPREC;
  248.                 else
  249.                     prec = DEFPREC;
  250.             }
  251.             /*
  252.              * softsign avoids negative 0 if _double is < 0 and
  253.              * no significant digits will be shown
  254.              */
  255.             if (_double < 0) {
  256.                 softsign = '-';
  257.                 _double = -_double;
  258.             }
  259.             else
  260.                 softsign = 0;
  261.             /*
  262.              * cvt may have to round up past the "start" of the
  263.              * buffer, i.e. ``intf("%.2f", (double)9.999);'';
  264.              * if the first char isn't NULL, it did.
  265.              */
  266.             *buf = NULL;
  267.             size = cvt(_double, prec, flags, &softsign, *fmt, buf,
  268.                 buf + sizeof(buf));
  269.             if (softsign && !nan)
  270.                 sign = '-';
  271.             nan = 0;
  272.             t = *buf ? buf : buf + 1;
  273.             goto pforw;
  274.         case 'n':
  275.             if (flags & LONGINT)
  276.                 *va_arg(argp, long *) = cnt;
  277.             else if (flags & SHORTINT)
  278.                 *va_arg(argp, short *) = cnt;
  279.             else
  280.                 *va_arg(argp, int *) = cnt;
  281.             break;
  282.         case 'O':
  283.             flags |= LONGINT;
  284.             /*FALLTHROUGH*/
  285.         case 'o':
  286.             ARG(unsigned);
  287.             base = 8;
  288.             goto nosign;
  289.         case 'p':
  290.             /*
  291.              * ``The argument shall be a pointer to void.  The
  292.              * value of the pointer is converted to a sequence
  293.              * of printable characters, in an implementation-
  294.              * defined manner.''
  295.              *    -- ANSI X3J11
  296.              */
  297.             /* NOSTRICT */
  298.             _ulong = (u_long)va_arg(argp, void *);
  299.             base = 16;
  300.             goto nosign;
  301.         case 's':
  302.             if (!(t = va_arg(argp, char *)))
  303.                 t = "(null)";
  304.             if (prec >= 0) {
  305.                 /*
  306.                  * can't use strlen; can only look for the
  307.                  * NUL in the first `prec' characters, and
  308.                  * strlen() will go further.
  309.                  */
  310.                 char *p, *memchr();
  311.  
  312.                 if (p = memchr(t, 0, prec)) {
  313.                     size = p - t;
  314.                     if (size > prec)
  315.                         size = prec;
  316.                 } else
  317.                     size = prec;
  318.             } else
  319.                 size = strlen(t);
  320.             sign = '\0';
  321.             goto pforw;
  322.         case 'U':
  323.             flags |= LONGINT;
  324.             /*FALLTHROUGH*/
  325.         case 'u':
  326.             ARG(unsigned);
  327.             base = 10;
  328.             goto nosign;
  329.         case 'X':
  330.             digs = "0123456789ABCDEF";
  331.             /* FALLTHROUGH */
  332.         case 'x':
  333.             ARG(unsigned);
  334.             base = 16;
  335.             /* leading 0x/X only if non-zero */
  336.             if (flags & ALT && _ulong != 0)
  337.                 flags |= HEXPREFIX;
  338.  
  339.             /* unsigned conversions */
  340. nosign:            sign = '\0';
  341.             /*
  342.              * ``... diouXx conversions ... if a precision is
  343.              * specified, the 0 flag will be ignored.''
  344.              *    -- ANSI X3J11
  345.              */
  346. number:            if ((dprec = prec) >= 0)
  347.                 flags &= ~ZEROPAD;
  348.  
  349.             /*
  350.              * ``The result of converting a zero value with an
  351.              * explicit precision of zero is no characters.''
  352.              *    -- ANSI X3J11
  353.              */
  354.             t = buf + BUF;
  355.             if (_ulong != 0 || prec != 0) {
  356.                 do {
  357.                     *--t = digs[_ulong % base];
  358.                     _ulong /= base;
  359.                 } while (_ulong);
  360.                 digs = "0123456789abcdef";
  361.                 if (flags & ALT && base == 8 && *t != '0')
  362.                     *--t = '0'; /* octal leading 0 */
  363.             }
  364.             size = buf + BUF - t;
  365.  
  366. pforw:
  367.             /*
  368.              * All reasonable formats wind up here.  At this point,
  369.              * `t' points to a string which (if not flags&LADJUST)
  370.              * should be padded out to `width' places.  If
  371.              * flags&ZEROPAD, it should first be prefixed by any
  372.              * sign or other prefix; otherwise, it should be blank
  373.              * padded before the prefix is emitted.  After any
  374.              * left-hand padding and prefixing, emit zeroes
  375.              * required by a decimal [diouxX] precision, then print
  376.              * the string proper, then emit zeroes required by any
  377.              * leftover floating precision; finally, if LADJUST,
  378.              * pad with blanks.
  379.              */
  380.  
  381.             /*
  382.              * compute actual size, so we know how much to pad
  383.              * fieldsz excludes decimal prec; realsz includes it
  384.              */
  385.             fieldsz = size + fpprec;
  386.             realsz = dprec > fieldsz ? dprec : fieldsz;
  387.             if (sign)
  388.                 realsz++;
  389.             if (flags & HEXPREFIX)
  390.                 realsz += 2;
  391.  
  392.             /* right-adjusting blank padding */
  393.             if ((flags & (LADJUST|ZEROPAD)) == 0 && width)
  394.                 for (n = realsz; n < width; n++)
  395.                     PUTC(' ');
  396.             /* prefix */
  397.             if (sign)
  398.                 PUTC(sign);
  399.             if (flags & HEXPREFIX) {
  400.                 PUTC('0');
  401.                 PUTC((char)*fmt);
  402.             }
  403.             /* right-adjusting zero padding */
  404.             if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
  405.                 for (n = realsz; n < width; n++)
  406.                     PUTC('0');
  407.             /* leading zeroes from decimal precision */
  408.             for (n = fieldsz; n < dprec; n++)
  409.                 PUTC('0');
  410.  
  411.             /* the string or number proper */
  412.             n = size;
  413.             if (fp->_cnt - n >= 0 && (fp->_flag & _IOLBF) == 0) {
  414.                 fp->_cnt -= n;
  415.                 bcopy(t, (char *)fp->_ptr, n);
  416.                 fp->_ptr += n;
  417.             } else
  418.                 while (--n >= 0)
  419.                     PUTC(*t++);
  420.             /* trailing f.p. zeroes */
  421.             while (--fpprec >= 0)
  422.                 PUTC('0');
  423.             /* left-adjusting padding (always blank) */
  424.             if (flags & LADJUST)
  425.                 for (n = realsz; n < width; n++)
  426.                     PUTC(' ');
  427.             /* finally, adjust cnt */
  428.             cnt += width > realsz ? width : realsz;
  429.             break;
  430.         case '\0':    /* "%?" prints ?, unless ? is NULL */
  431.             return (cnt);
  432.         default:
  433.             PUTC((char)*fmt);
  434.             cnt++;
  435.         }
  436.     }
  437.     /* NOTREACHED */
  438. }
  439.  
  440. static
  441. cvt(number, prec, flags, signp, fmtch, startp, endp)
  442.     double number;
  443.     register int prec;
  444.     int flags;
  445.     u_char fmtch;
  446.     char *signp, *startp, *endp;
  447. {
  448.     register char *p, *t;
  449.     register double fract;
  450.     int dotrim, expcnt, gformat;
  451.     double integer, tmp, modf();
  452.     char *exponent(), *round();
  453.  
  454. #ifdef hp300
  455.     if (expcnt = isspecial(number, startp, signp))
  456.         return(expcnt);
  457. #endif
  458. #ifdef __GO32__
  459.     if (expcnt = isspecial(number, startp))
  460.         return(expcnt);
  461. #endif
  462.  
  463.     dotrim = expcnt = gformat = 0;
  464.     fract = modf(number, &integer);
  465.  
  466.     /* get an extra slot for rounding. */
  467.     t = ++startp;
  468.  
  469.     /*
  470.      * get integer portion of number; put into the end of the buffer; the
  471.      * .01 is added for modf(356.0 / 10, &integer) returning .59999999...
  472.      */
  473.     for (p = endp - 1; integer; ++expcnt) {
  474.         tmp = modf(integer / 10, &integer);
  475.         *p-- = tochar((int)((tmp + .01) * 10));
  476.     }
  477.     switch(fmtch) {
  478.     case 'f':
  479.         /* reverse integer into beginning of buffer */
  480.         if (expcnt)
  481.             for (; ++p < endp; *t++ = *p);
  482.         else
  483.             *t++ = '0';
  484.         /*
  485.          * if precision required or alternate flag set, add in a
  486.          * decimal point.
  487.          */
  488.         if (prec || flags&ALT)
  489.             *t++ = '.';
  490.         /* if requires more precision and some fraction left */
  491.         if (fract) {
  492.             if (prec)
  493.                 do {
  494.                     fract = modf(fract * 10, &tmp);
  495.                     *t++ = tochar((int)tmp);
  496.                 } while (--prec && fract);
  497.             if (fract)
  498.                 startp = round(fract, (int *)NULL, startp,
  499.                     t - 1, (char)0, signp);
  500.         }
  501.         for (; prec--; *t++ = '0');
  502.         break;
  503.     case 'e':
  504.     case 'E':
  505. eformat:    if (expcnt) {
  506.             *t++ = *++p;
  507.             if (prec || flags&ALT)
  508.                 *t++ = '.';
  509.             /* if requires more precision and some integer left */
  510.             for (; prec && ++p < endp; --prec)
  511.                 *t++ = *p;
  512.             /*
  513.              * if done precision and more of the integer component,
  514.              * round using it; adjust fract so we don't re-round
  515.              * later.
  516.              */
  517.             if (!prec && ++p < endp) {
  518.                 fract = 0;
  519.                 startp = round((double)0, &expcnt, startp,
  520.                     t - 1, *p, signp);
  521.             }
  522.             /* adjust expcnt for digit in front of decimal */
  523.             --expcnt;
  524.         }
  525.         /* until first fractional digit, decrement exponent */
  526.         else if (fract) {
  527.             /* adjust expcnt for digit in front of decimal */
  528.             for (expcnt = -1;; --expcnt) {
  529.                 fract = modf(fract * 10, &tmp);
  530.                 if (tmp)
  531.                     break;
  532.             }
  533.             *t++ = tochar((int)tmp);
  534.             if (prec || flags&ALT)
  535.                 *t++ = '.';
  536.         }
  537.         else {
  538.             *t++ = '0';
  539.             if (prec || flags&ALT)
  540.                 *t++ = '.';
  541.         }
  542.         /* if requires more precision and some fraction left */
  543.         if (fract) {
  544.             if (prec)
  545.                 do {
  546.                     fract = modf(fract * 10, &tmp);
  547.                     *t++ = tochar((int)tmp);
  548.                 } while (--prec && fract);
  549.             if (fract)
  550.                 startp = round(fract, &expcnt, startp,
  551.                     t - 1, (char)0, signp);
  552.         }
  553.         /* if requires more precision */
  554.         for (; prec--; *t++ = '0');
  555.  
  556.         /* unless alternate flag, trim any g/G format trailing 0's */
  557.         if (gformat && !(flags&ALT)) {
  558.             while (t > startp && *--t == '0');
  559.             if (*t == '.')
  560.                 --t;
  561.             ++t;
  562.         }
  563.         t = exponent(t, expcnt, fmtch);
  564.         break;
  565.     case 'g':
  566.     case 'G':
  567.         /* a precision of 0 is treated as a precision of 1. */
  568.         if (!prec)
  569.             ++prec;
  570.         /*
  571.          * ``The style used depends on the value converted; style e
  572.          * will be used only if the exponent resulting from the
  573.          * conversion is less than -4 or greater than the precision.''
  574.          *    -- ANSI X3J11
  575.          */
  576.         if (expcnt > prec || !expcnt && fract && fract < .0001) {
  577.             /*
  578.              * g/G format counts "significant digits, not digits of
  579.              * precision; for the e/E format, this just causes an
  580.              * off-by-one problem, i.e. g/G considers the digit
  581.              * before the decimal point significant and e/E doesn't
  582.              * count it as precision.
  583.              */
  584.             --prec;
  585.             fmtch -= 2;        /* G->E, g->e */
  586.             gformat = 1;
  587.             goto eformat;
  588.         }
  589.         /*
  590.          * reverse integer into beginning of buffer,
  591.          * note, decrement precision
  592.          */
  593.         if (expcnt)
  594.             for (; ++p < endp; *t++ = *p, --prec);
  595.         else
  596.             *t++ = '0';
  597.         /*
  598.          * if precision required or alternate flag set, add in a
  599.          * decimal point.  If no digits yet, add in leading 0.
  600.          */
  601.         if (prec || flags&ALT) {
  602.             dotrim = 1;
  603.             *t++ = '.';
  604.         }
  605.         else
  606.             dotrim = 0;
  607.         /* if requires more precision and some fraction left */
  608.         while (prec && fract) {
  609.             fract = modf(fract * 10, &tmp);
  610.             *t++ = tochar((int)tmp);
  611.             prec--;
  612.         }
  613.         if (fract)
  614.             startp = round(fract, (int *)NULL, startp, t - 1,
  615.                     (char)0, signp);
  616.         /* alternate format, adds 0's for precision, else trim 0's */
  617.         if (flags&ALT)
  618.             for (; prec--; *t++ = '0');
  619.         else if (dotrim) {
  620.             while (t > startp && *--t == '0');
  621.             if (*t != '.')
  622.                 ++t;
  623.         }
  624.     }
  625.     return(t - startp);
  626. }
  627.  
  628. static char *
  629. round(fract, exp, start, end, ch, signp)
  630.     double fract;
  631.     int *exp;
  632.     register char *start, *end;
  633.     char ch, *signp;
  634. {
  635.     double tmp;
  636.     double modf();
  637.  
  638.     if (fract)
  639.         (void)modf(fract * 10, &tmp);
  640.     else
  641.         tmp = todigit(ch);
  642.     if (tmp > 4)
  643.         for (;; --end) {
  644.             if (*end == '.')
  645.                 --end;
  646.             if (++*end <= '9')
  647.                 break;
  648.             *end = '0';
  649.             if (end == start) {
  650.                 if (exp) {    /* e/E; increment exponent */
  651.                     *end = '1';
  652.                     ++*exp;
  653.                 }
  654.                 else {        /* f; add extra digit */
  655.                     *--end = '1';
  656.                     --start;
  657.                 }
  658.                 break;
  659.             }
  660.         }
  661.     /* ``"%.3f", (double)-0.0004'' gives you a negative 0. */
  662.     else if (*signp == '-')
  663.         for (;; --end) {
  664.             if (*end == '.')
  665.                 --end;
  666.             if (*end != '0')
  667.                 break;
  668.             if (end == start)
  669.                 *signp = 0;
  670.         }
  671.     return(start);
  672. }
  673.  
  674. static char *
  675. exponent(p, exp, fmtch)
  676.     register char *p;
  677.     register int exp;
  678.     u_char fmtch;
  679. {
  680.     register char *t;
  681.     char expbuf[MAXEXP];
  682.  
  683.     *p++ = fmtch;
  684.     if (exp < 0) {
  685.         exp = -exp;
  686.         *p++ = '-';
  687.     }
  688.     else
  689.         *p++ = '+';
  690.     t = expbuf + MAXEXP;
  691.     if (exp > 9) {
  692.         do {
  693.             *--t = tochar(exp % 10);
  694.         } while ((exp /= 10) > 9);
  695.         *--t = tochar(exp);
  696.         for (; t < expbuf + MAXEXP; *p++ = *t++);
  697.     }
  698.     else {
  699.         *p++ = '0';
  700.         *p++ = tochar(exp);
  701.     }
  702.     return(p);
  703. }
  704.  
  705. #ifdef hp300
  706. isspecial(d, bufp, signp)
  707.     double d;
  708.     char *bufp, *signp;
  709. {
  710.     register struct IEEEdp {
  711.         unsigned sign:1;
  712.         unsigned exp:11;
  713.         unsigned manh:20;
  714.         unsigned manl:32;
  715.     } *ip = (struct IEEEdp *)&d;
  716.  
  717.     if (ip->exp != 0x7ff)
  718.         return(0);
  719.     if (ip->manh || ip->manl)
  720.         (void)strcpy(bufp, "NaN");
  721.     else
  722.         (void)strcpy(bufp, "Inf");
  723.     return(3);
  724. }
  725. #endif
  726.  
  727. #ifdef __GO32__
  728. static int isspecial(d, bufp)
  729.     double d;
  730.     char *bufp;
  731. {
  732.         register struct IEEEdp {
  733.             unsigned manl:32;
  734.             unsigned manh:20;
  735.             unsigned exp:11;
  736.             unsigned sign:1;
  737.     } *ip = (struct IEEEdp *)&d;
  738.  
  739.     if (ip->exp != 0x7ff)
  740.         return(0);
  741.     if (ip->manh || ip->manl)
  742.         {
  743.         strcpy(bufp, "NaN");
  744.             nan = 1; /* kludge: we don't need the sign,  it's not nice
  745.                     but it should work */
  746.         }
  747.     else
  748.         (void)strcpy(bufp, "Inf");
  749.         return(3);
  750. }
  751. #endif
  752.  
  753.